﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ufida.u9.ait.openapi.utils;
using UFIDA.U9.Base;
using UFIDA.U9.Base.Currency;
using UFIDA.U9.Base.Doc;
using UFIDA.U9.Base.Memo;
using UFIDA.U9.Base.UOM;
using UFIDA.U9.CBO.Enums;
using UFIDA.U9.CBO.FI.Tax;
using UFIDA.U9.CBO.HR.Department;
using UFIDA.U9.CBO.HR.Operator;
using UFIDA.U9.CBO.SCM.Customer;
using UFIDA.U9.CBO.SCM.Customs;
using UFIDA.U9.CBO.SCM.Enums;
using UFIDA.U9.CBO.SCM.InstalmentRecScheduleTemplate;
using UFIDA.U9.CBO.SCM.Item;
using UFIDA.U9.CBO.SCM.PreRecPolicy;
using UFIDA.U9.CBO.SCM.ProjectTask;
using UFIDA.U9.SM.Enums;
using UFIDA.U9.SM.InstalmentRecSchedule;
using UFIDA.U9.SM.SO;
using UFSoft.UBF.Business;

namespace ufida.u9.ait.openapi
{
    internal class SOBase
    {
        /// <summary>
        /// SO行关闭
        /// </summary>
        /// <param name="line"></param>
        /// <returns></returns>
        public static SOLine CloseSOLine(SOLine line)
        {
            //参考代码 CloseSOShipLineBP
            foreach (var shipline in line.SOShiplines)
            {
                shipline.SetBizCloseStatus();
                shipline.CloseDate = shipline.SOLine.SO.CurrencyDateTime();
                shipline.CloseReason = SOCloseReason.ManualClose;
                shipline.SOLine.SO.ServiceModify = ModifyEnum.SOCloseModify;
            }

            return line;
        }

        public static SO SubmitDoc(SO doc)
        {
            doc = doc.Key.GetEntity();
            if (doc.Status != SODocStatusEnum.Open) 
                throw new Exception($"单号[{doc.DocNo}]状态不为开立,不能提交");
            //提交
            SOStatusTransferBP bp1 = new SOStatusTransferBP();
            bp1.SOKeyDTOList = new List<SOKeyDTO>() {
                new SOKeyDTO(doc.Key, doc.SysVersion, SODocStatusEnum.Approving)
            };
            List<SOStatusDTO> retdto1 = bp1.Do();

            return doc;
        }

        /// <summary>
        /// 创建销售订单分期收款计划
        /// </summary>
        /// <param name="dto">分期收款计划模板DTO</param>
        /// <param name="doc">销售订单</param>
        /// <returns></returns>
        public static SO CreateInstalmentRecSchedule(InstalmentRecScheduleAITDTOData dto, SO doc)
        {
            String path = $"DocID={doc.ID}";
            InstalmentRecSchedule rec = InstalmentRecSchedule.Finder.Find(path);
            if (rec == null)
            {
                //查找 分期收款计划模板
                InstalmentRecScheduleTemplate temp = EntityUtils.GetEntityByCode<InstalmentRecScheduleTemplate>(dto.InstalmentRecScheduleTemplate, true);

                using (ISession session = Session.Open())
                {
                    //头处理
                    rec = InstalmentRecSchedule.Create();
                    rec.Org = doc.Org;
                    rec.AccountOrg= doc.AccountOrg;
                    rec.AC=doc.AC;
                    rec.TotalReceiveMoney = doc.TotalMoneyAC;
                    rec.TotalMoney=doc.TotalMoneyAC;
                    rec.SODocNo = doc.DocNo;
                    rec.DocID = doc.ID;
                    rec.Payer = doc.Payer;
                    rec.OrderBy = doc.OrderBy;
                    rec.IsMoneyPriority = true;
                    rec.InstalmentRecScheduleTemplate = temp;
                    rec.CustomerSite = doc.PayerSite;
                    rec.ActivityNo = SMActivityEnum.SOUIUpd;

                    //行处理
                    decimal sum = 0;
                    for(int i = 0; i < temp.InstalmentRecScheduleTemplateLine.Count; i++)
                    {
                        InstalmentRecScheduleTemplateLine tline = temp.InstalmentRecScheduleTemplateLine[i];
                        InstalmentRecScheduleLine line = InstalmentRecScheduleLine.Create(rec);

                        line.PlanReceivePercent = tline.RecPercent;
                        line.PlanReceiveMoney = rec.TotalReceiveMoney * line.PlanReceivePercent;
                        line.PlanReceiveMoney = U9Utils.GetRoundMoney(rec.AC, line.PlanReceiveMoney);//精度处理
                        sum += line.PlanReceiveMoney;
                        line.PlanReceiveDate = DateTime.Now;
                        line.InstalmentType = tline.InstalmentType;
                        line.DocLineNo = i * 10 + 10;
                        line.ActualARDate = DateTime.Now;
                        if (i == temp.InstalmentRecScheduleTemplateLine.Count - 1)
                        {
                            //最后一行,处理尾差
                            line.PlanReceiveMoney += rec.TotalReceiveMoney - sum;
                        }
                    }

                    session.Commit();
                }
            }
            return doc;
        }

        public static SO ApproveDoc(SO doc)
        {
            doc = doc.Key.GetEntity();
            if (doc.Status != SODocStatusEnum.Approving)
                throw new Exception($"单号[{doc.DocNo}]状态不为提交,不能审核");
            //审核
            SOStatusTransferBP bp = new SOStatusTransferBP();
            bp.SOKeyDTOList = new List<SOKeyDTO>() {
                new SOKeyDTO(doc.Key, doc.SysVersion, SODocStatusEnum.Approved)
            };
            List<SOStatusDTO> retdto = bp.Do();
            return doc;
        }

        /// <summary>
        /// 修改销售订单
        /// </summary>
        /// <param name="doc"></param>
        /// <param name="dto"></param>
        public static SO UpdateDoc(SOAITDTOData dto, SO doc)
        {
            if (doc.Status == SODocStatusEnum.Close
                || doc.Status == SODocStatusEnum.CloseExcess
                || doc.Status == SODocStatusEnum.CloseShort)
                throw new Exception($"订单[{doc.DocNo}]已经关闭");
            if (doc.Status == SODocStatusEnum.Approved && doc.DocumentType.IsAMADoc == false)
                throw new Exception($"订单[{doc.DocNo}]已经审核且参数[核准后可改]未选中");

            using (ISession session = Session.Open())
            {
                UpdateHead(doc, dto);
                UpdateLines(doc, dto);
                session.Commit();
            }

            return doc;
        }

        private static void UpdateLines(SO doc, SOAITDTOData dto)
        {
            foreach (var linedto in dto.SOLines)
            {
                if (linedto.DocLineNo <= 0) throw new Exception("DocLineNo必填!");
            }

            //新旧数据对比
            List<ObjUtils.OperItem> operItems = ObjUtils.CompareList(dto.SOLines, doc.SOLines, "DocLineNo");
            foreach (var item in operItems)
            {
                if(item.oper== ObjUtils.OperEnum.add)
                {
                    //新增行
                    SOLineAITDTOData linedto = (SOLineAITDTOData)item.item1;
                    SOLine line = SOLine.Create(doc);
                    line.DocLineNo = linedto.DocLineNo;
                    UpdateLine(line, linedto);
                }
                else if(item.oper == ObjUtils.OperEnum.update)
                {
                    //修改行
                    SOLineAITDTOData linedto=(SOLineAITDTOData)item.item1;
                    SOLine line = (SOLine)item.item2;
                    line.ActionSrc = SMActivityEnum.OBAUpdate;
                    UpdateLine(line, linedto);
                }else if (item.oper == ObjUtils.OperEnum.delete)
                {
                    //删除行
                    //此处进行行关闭,不再删除
                    SOLine line = (SOLine)item.item2;
                    //line.Remove();
                    CloseSOLine(line);
                }
            }
        }

        /// <summary>
        /// 创建销售订单
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        public static SO CreateDoc(SOAITDTOData dto)
        {
            SO doc = null;

            using (ISession session = Session.Open())
            {
                doc = SO.Create();
                doc = UpdateHead(doc, dto);
                doc = CreateLines(doc, dto);

                session.Commit();
            }
            return doc;
        }
        private static void UpdateLine(SOLine line, SOLineAITDTOData linedto)
        {
            SO doc = line.SO;

            LineDefault(line, linedto);
            LineQty(line, linedto);
            LineMny(line, linedto);
            //创建 计划行
            UpdateShipLine(doc, line,linedto);
            //创建 订单税表
            UpdateSOTaxs(line);
        }

        private static void LineMny(SOLine line, SOLineAITDTOData linedto)
        {
            SO doc = line.SO;
            ItemMaster item = line.ItemInfo.ItemID;

            //赠品不做金额计算
            if (line.FreeType.Value >= 0) return;

            LineTaxSchedule(line, linedto);

            if (linedto.FinallyPriceTC == 0) throw new Exception("FinallyPriceTC必填");
            line.FinallyPriceTC = linedto.FinallyPriceTC;//最终价 含税价
            line.OrderPriceTC = linedto.FinallyPriceTC;

            line.TotalMoneyTC = linedto.TotalMoneyTC;//价税合计(原币)
            line.TotalMoneyAC = line.TotalMoneyTC * doc.TCToACExchRate;//价税合计(核币)
            line.TotalMoneyAC = EntityUtils.GetRoundMny(doc.AC, line.TotalMoneyAC);//精度
            line.InvoiceMaxMoneyAC = line.TotalMoneyAC;//可开票金额
            line.TotalMoneyFC = line.TotalMoneyAC * doc.ACToFCRate;//价税合计(核币)
            line.TotalMoneyFC = EntityUtils.GetRoundMny(doc.FC, line.TotalMoneyFC);//精度

            //未税金额=价税合计/(1+税率)
            line.NetMoneyTC = line.TotalMoneyTC / (1 + line.TaxRate);//未税金额(原币)
            line.NetMoneyTC = EntityUtils.GetRoundMny(doc.TC, line.NetMoneyTC);//精度
            line.NetMontyAC = line.TotalMoneyAC / (1 + line.TaxRate);//未税金额(核币)
            line.NetMontyAC = EntityUtils.GetRoundMny(doc.AC, line.NetMontyAC);//精度
            line.NetMoneyFC = line.TotalMoneyFC / (1 + line.TaxRate);//未税金额(核币)
            line.NetMoneyFC = EntityUtils.GetRoundMny(doc.FC, line.NetMoneyFC);//精度

            //税额=价税合计-未税金额
            line.TaxMoneyTC = line.TotalMoneyTC - line.NetMoneyTC;
            line.TaxMoneyAC = line.TotalMoneyAC - line.NetMontyAC;
            line.TaxMoneyFC = line.TotalMoneyFC - line.NetMoneyFC;
        }

        private static void LineTaxSchedule(SOLine line, SOLineAITDTOData linedto)
        {
            SO doc = line.SO;
            ItemMaster item = line.ItemInfo.ItemID;
            //税组合
            if (linedto.TaxSchedule != null)
            {
                //优先传入
                line.TaxSchedule = EntityUtils.GetEntityByCode<TaxSchedule>(linedto.TaxSchedule.Code);
            }
            else if (item.PurchaseInfo.PurchaseTaxSchedule != null)
            {
                //其次料品
                line.TaxSchedule = item.PurchaseInfo.PurchaseTaxSchedule;
            }
            else if (doc.TaxSchedule != null)
            {
                //其次单头
                line.TaxSchedule = doc.TaxSchedule;
            }
            if (line.TaxSchedule == null) throw new Exception("行税组合为空");
            line.TaxRate = line.TaxSchedule.TaxScheduleTaxs[0].Tax.TaxRate;//税率
        }

        /// <summary>
        /// 计量单位/数量/转换率
        /// </summary>
        /// <param name="line"></param>
        /// <param name="linedto"></param>
        /// <exception cref="Exception"></exception>
        private static void LineQty(SOLine line, SOLineAITDTOData linedto)
        {
            SO doc = line.SO;
            ItemMaster item = line.ItemInfo.ItemID;
            //计量单位
            line.WeightUOM = item.WeightUom;
            line.VolumeUOM = item.BulkUom;
            if (linedto.TU == null)
            {
                line.TU = item.SalesUOM;
                line.TBU = item.SalesUOM.BaseUOM;
            }
            else
            {
                UOM uom = EntityUtils.GetEntityByCode<UOM>(linedto.TU.Code);
                line.TU = uom;
                line.TBU = uom.BaseUOM;
            }
            if (linedto.PU == null)
            {
                line.PU = item.PriceUOM;
                line.PBU = item.PriceUOM.BaseUOM;
            }
            else
            {
                UOM uom = EntityUtils.GetEntityByCode<UOM>(linedto.PU.Code);
                line.PU = uom;
                line.PBU = uom.BaseUOM;
            }

            //数量
            if (linedto.OrderByQtyTU == 0) throw new Exception("OrderByQtyTU 为空");
            line.OrderByQtyTU = linedto.OrderByQtyTU;//交易单位数量
            //计价单位数量
            if (linedto.OrderByQtyPU > 0)
            {
                line.OrderByQtyPU = linedto.OrderByQtyPU;
            }
            else
            {
                line.OrderByQtyPU = linedto.OrderByQtyTU * U9Utils.GetUom2Rate(line.TU, line.PU, item);
            }
            //转换率
            line.TBUToPBURate = line.OrderByQtyPU / line.OrderByQtyTU;//销售-计价
            line.TBUToCBURate = line.TBUToPBURate;//销售-成本
        }

        private static void LineDefault(SOLine line, SOLineAITDTOData linedto)
        {
            SO doc = line.SO;

            line.Org = doc.Org;
            //料品/单位
            if (linedto.ItemInfo == null) throw new Exception("ItemInfo 为空");
            ItemMaster item = EntityUtils.GetEntityByCode<ItemMaster>(linedto.ItemInfo.ItemCode);
            line.ItemInfo = new ItemInfo()
            {
                ItemID = item,
                ItemCode = item.Code,
                ItemName = item.Name,
            };

            //扩展字段处理
            if (linedto.DescFlexField != null)
            {
                line.DescFlexField = new UFIDA.U9.Base.FlexField.DescFlexField.DescFlexSegments();
                DTOUtils.DTOPropCopy(linedto.DescFlexField, line.DescFlexField);
            }

            //单行备注
            if (linedto.Memo != null)
            {
                if (line.SOMemoes != null && line.SOMemoes.Count > 0)
                {
                    line.SOMemoes[0].Description = linedto.Memo;
                }
                else
                {
                    SOMemo memo = SOMemo.Create(line);
                    memo.LineNO = 10;
                    memo.Description = linedto.Memo;
                    memo.DocMemoType = DocMemoTypeEnum.LineHead;
                    memo.IsForAfterSold = true;
                    memo.IsForCustomer = true;
                    memo.IsForFinancial = true;
                    memo.IsForInv = true;
                    memo.IsForManufacture = true;
                    memo.IsForPurchase = true;
                    memo.IsForRD = true;
                    memo.IsForSupplier = true;
                }
            }

            //其它赋值
            if (line.Status == SODocStatusEnum.Close
                || line.Status == SODocStatusEnum.CloseExcess
                || line.Status == SODocStatusEnum.CloseShort)
                throw new Exception($"订单[{doc.DocNo}],行[{line.DocLineNo}]已经关闭");

            line.Status = doc.Status;
            if (linedto.FreeType >= 0) line.FreeType = FreeTypeEnum.GetFromValue(linedto.FreeType);//免费品(赠品)类型
            line.ShipToSite = doc.ShipToSite;
            line.Project = EntityUtils.GetEntityByCode<Project>(linedto.Project);//项目
            line.Memo = linedto.Memo;
            line.TUtoTBURate = 1;
            line.TBUToPBURate = 1;
            line.TBUToIBURate = 1;
            line.TBUToCBURate = 1;
            line.PUToPBURate = 1;
            line.TradePathEditalbe = true;
            line.ShipToSite = doc.ShipToSite;
            //收款条件
            if (doc.OrderBy.Customer.CustomerSites[0].PaymentTerm != null)
            {
                //客户位置 收款条件
                line.RecTerm = doc.OrderBy.Customer.CustomerSites[0].PaymentTerm;
            }
            else
            {
                //客户 收款条件
                line.RecTerm = doc.OrderBy.Customer.RecervalTerm;
            }
            line.PTOMItemFlag = Guid.Empty;
            line.PriceSource = PriceSourceEnum.Custom;
            line.PreRecObject = doc.PreRecObject;
            line.OriginalPriceIncludeTax = true;
            line.IsRecTermAdaptable = true;
            line.IsPriceModify = true;
            line.IsPriceListModify = true;
            line.IsInvoice = true;
            line.IsEngrossCreditLimit = true;
            line.IsChangeableTU = true;
            line.IsChangeableTBUToPBURate = true;
            line.ISChangeableTask = true;
            line.IsChangeablePU = true;
            line.IsChangeableProject = true;
            line.IsChangeableItemVersion = true;
            line.IsCanReturn = true;
            line.DiscountRate = 1;
            line.CreditObj = doc.PayerSite;
            line.BillToSite = doc.BillToSite;
        }

        private static SO CreateLines(SO doc, SOAITDTOData dto)
        {
            int DocLineNo = 0;
            foreach (var linedto in dto.SOLines)
            {
                DocLineNo += 10;

                SOLine line = SOLine.Create(doc);
                if (linedto.DocLineNo == 0)
                    line.DocLineNo = DocLineNo;
                else
                    line.DocLineNo = linedto.DocLineNo;
                UpdateLine(line, linedto);
                
            }

            return doc;
        }

        private static void UpdateSOTaxs(SOLine line)
        {
            //赠品无税额
            if (line.TaxMoneyTC == 0) return;

            SOTax taxline = null;
            if (line.SOTaxes == null || line.SOTaxes.Count == 0)
                taxline = SOTax.Create(line);
            else
                taxline = line.SOTaxes[0];

            taxline.TaxRate = line.TaxRate;
            taxline.TaxMoneyTC = line.TaxMoneyTC;
            taxline.TaxMoneyFunC = line.TaxMoneyFC;
            taxline.TaxMoneyAC = line.TaxMoneyAC;
            taxline.Tax = line.TaxSchedule.TaxScheduleTaxs[0].Tax;
            
            taxline.LineNum = 1;
        }

        private static void UpdateShipLine(SO doc, SOLine line,SOLineAITDTOData linedto)
        {
            SOShipline shipLine = null;
            if (line.SOShiplines == null || line.SOShiplines.Count == 0)
            {
                shipLine = SOShipline.Create(line);
                shipLine.DocSubLineNo = 10;
            }
            else
                shipLine = line.SOShiplines[0];
            shipLine.ActionSrc = line.ActionSrc;

            //料品/数量/单位
            shipLine.ItemInfo = line.ItemInfo;
            shipLine.TU = line.TU;
            shipLine.PU = line.PU;
            shipLine.PBU = line.PBU;
            shipLine.TBU = line.TBU;
            shipLine.ShipPlanQtyTU = line.OrderByQtyTU;
            shipLine.ShipPlanQtyPU = line.OrderByQtyPU;
            shipLine.ShipPlanQtyIU = line.OrderByQtyTU;
            shipLine.TUBaseToPUBaseRate = shipLine.ShipPlanQtyPU / shipLine.ShipPlanQtyTU; //销售-计价
            //单价/金额
            shipLine.FinallyPriceTC = line.FinallyPriceTC;
            shipLine.TotalMoneyTC = line.TotalMoneyTC;
            shipLine.TotalMoneyAC = line.TotalMoneyAC;
            shipLine.InvoiceMaxMoneyAC = line.InvoiceMaxMoneyAC;
            shipLine.TotalMoneyFC = line.TotalMoneyFC;
            shipLine.NetMoneyTC = line.NetMoneyTC;
            shipLine.NetMoneyAC = line.NetMontyAC;
            shipLine.NetMoneyFC = line.NetMoneyFC;
            //组织
            shipLine.SupplyOrg = doc.Org;
            shipLine.ShiperOrg = doc.Org;
            //日期
            if (!string.IsNullOrEmpty(linedto.RequireDate))
            {
                shipLine.RequireDate=DateTime.Parse(linedto.RequireDate);//交期
            }
            else
            {
                shipLine.RequireDate = doc.BusinessDate;
            }
            shipLine.PlanDate = shipLine.RequireDate;
            shipLine.DeliveryDate = shipLine.RequireDate;
            shipLine.AffirmShipDate = shipLine.RequireDate;

            //其它
            shipLine.Status = line.Status;
            shipLine.Project = line.Project;
            shipLine.TUToTBURate = 1;
            shipLine.PUToPBURate = 1;
            shipLine.IsMRPRequire = true;
            shipLine.ISChangeableTask = true;
            shipLine.IsChangeableProject = true;
            shipLine.IsChangeableItemVersion = true;
            shipLine.TradePathEditalbe = true;
            shipLine.SeibanAlterable = SeibanAlterableEnum.NotChangedSelfCreate;
            shipLine.DemandTransformType = UFIDA.U9.CBO.SCM.Item.DemandTransTypeEnum.CurrentOrgShipment;
            shipLine.ShipToSite = line.ShipToSite;
            shipLine.SupplySource = UFIDA.U9.CBO.SCM.Item.SupplySourceEnum.CurrentOrg;
            UpdateSOInstalmentTerm(shipLine);
        }
        /// <summary>
        /// 更新SO时,需要同步更新SO计划行的 立账分期子表/收款分期子表 处理
        /// 新增时,不用处理
        /// </summary>
        /// <param name="shipLine"></param>
        private static void UpdateSOInstalmentTerm(SOShipline shipLine)
        {
            SOLine line = shipLine.SOLine;

            //立账分期子表处理
            if (shipLine.SOInstalmentTerm != null && shipLine.SOInstalmentTerm.Count > 0)
            {
                //修改时,需要同步立账分期子表的数据
                SOInstalmentTerm term = shipLine.SOInstalmentTerm[0];

                term.ShipPlanQtyTU = shipLine.ShipPlanQtyTU;//计划出货数量
                term.ShipPlanQtyPU = shipLine.ShipPlanQtyTU;//计划出货数量

                term.NetPriceAC = line.NetMoneyTC / term.ShipPlanQtyTU; //未税单价(核币)
                term.Money = line.TotalMoneyTC; //立账金额
                term.TotalMoneyAC = line.TotalMoneyTC;//价税合计
                term.NetMoneyAC = line.NetMoneyTC; //未税金额(核币)
                term.TaxMoneyAC = line.TaxMoneyTC; //税额(核币)
                term.TaxPriceAC = line.FinallyPriceTC;//税额(核币)

                //收款分期子表处理
                if (term.SOInstalmentRecTerm != null && term.SOInstalmentRecTerm.Count > 0)
                {
                    SOInstalmentRecTerm rec = term.SOInstalmentRecTerm[0];

                    rec.TotalMoneyAC = term.TotalMoneyAC; //价税合计(核币)
                    rec.TaxPriceAC = term.TaxMoneyAC; //税额(核币)
                    rec.ReceiveQtyTU = term.ShipPlanQtyTU;//收款数量
                    rec.ReceiveQtyPU = term.ShipPlanQtyTU;//收款数量
                    rec.NetPriceAC = term.NetPriceAC;//未税金额
                    rec.Money = term.Money;//收款金额
                }
            }
        }
        /// <summary>
        /// 单头修改
        /// 包含 新增时,审核后 的修改
        /// </summary>
        /// <param name="doc"></param>
        /// <param name="dto"></param>
        /// <returns></returns>
        private static SO UpdateHead(SO doc, SOAITDTOData dto)
        {
            if(doc.Status==null||doc.Status==SODocStatusEnum.Empty)
                doc.Status = SODocStatusEnum.Open;

            //doc.DocNo = dto.DocNo;
            if (dto.BusinessDate != null)
            {
                doc.BusinessDate = DateTime.Parse(dto.BusinessDate);
            }
            else
            {
                doc.BusinessDate = DateTime.Now;
            }
            //组织
            doc.Org = Context.LoginOrg;
            doc.InvoiceOrg = Context.LoginOrg;
            doc.ExecOrg = Context.LoginOrg;
            doc.BalanceOrg = Context.LoginOrg;
            doc.AccountOrg = Context.LoginOrg;
            
            //客户/客户位置
            if (String.IsNullOrEmpty(dto.OrderBy?.Code)) throw new Exception($"OrderBy 为空");
            Customer customer = EntityUtils.GetEntityByCode<Customer>(dto.OrderBy,true);
            doc.OrderBy = new CustomerMISCInfo()
            {
                Code = customer.Code,
                Customer = customer,
                Name = customer.Name,
                ShortName = customer.ShortName,
            };
            doc.Payer = doc.OrderBy;
            if (customer.CustomerSites == null || customer.CustomerSites.Count == 0)
                throw new Exception($"客户[{customer.Code}]的客户位置为空");
            doc.PayerSite = new CustomerSiteMISCInfo()
            {
                Code = customer.Code,
                CustomerSite = customer.CustomerSites[0],
                Name = customer.Name,
            };
            doc.ShipToSite = doc.PayerSite;
            doc.BillToSite = doc.PayerSite;

            //税组合
            if (String.IsNullOrEmpty(dto.TaxSchedule?.Code))
            {
                doc.TaxSchedule = EntityUtils.GetEntityByCode<TaxSchedule>(dto.TaxSchedule);
            }
            else if (customer.CustomerSites[0].TaxSchedule != null)
            {
                //客户位置税组合
                doc.TaxSchedule=customer.CustomerSites[0].TaxSchedule;
            }
            else if (customer.TaxSchedule != null)
            {
                //客户税组合
                doc.TaxSchedule = customer.TaxSchedule;
            }

            //记账期间
            doc.KeepAccountPeriod = EntityUtils.getPostPeriod(doc.BusinessDate);
            //单据类型
            if (dto.DocumentType == null) throw new Exception($"DocumentType 为空");
            doc.DocumentType = EntityUtils.GetEntityByCode<SODocType>(dto.DocumentType.Code);
            //币种/汇率
            doc.TC = EntityUtils.GetEntityByCode<Currency>(dto.TC);//交易币
            if (doc.TC == null)
            {
                doc.TC = EntityUtils.GetEntityByCode<Currency>("C001");//默认人民币
            }
            doc.AC = EntityUtils.GetEntityByCode<Currency>(dto.AC);//核币
            if(doc.AC == null)
            {
                doc.AC = doc.TC;
            }
            doc.FC = EntityUtils.GetEntityByCode<Currency>(dto.FC);//本币
            if (doc.FC == null)
            {
                doc.FC = EntityUtils.GetEntityByCode<Currency>("C001");//默认人民币
            }
            doc.TCToACExchRate = 1;//原币-核币汇率
            doc.ACToFCRate = 1;//核币-本币汇率
            //原币-核币汇率
            if (doc.TC.ID != doc.AC.ID)
            {
                
                if (dto.TCToACExchRate > 0)
                {
                    doc.TCToACExchRate = dto.TCToACExchRate;
                }
                else
                {
                    //查找U9汇率
                    string path = $"FromCurrency={doc.TC.ID} and ToCurrency={doc.AC.ID} and Date='{dto.BusinessDate}'";
                    ExchangeRate er = EntityUtils.GetEntityByPath<ExchangeRate>(path);
                    doc.TCToACExchRate = er.Rate;//汇率
                }
            }
            //核币-本币汇率
            if (doc.AC.ID != doc.FC.ID)
            {

                if (dto.ACToFCRate > 0)
                {
                    doc.ACToFCRate = dto.ACToFCRate;
                }
                else
                {
                    //查找U9汇率
                    string path = $"FromCurrency={doc.AC.ID} and ToCurrency={doc.FC.ID} and Date='{dto.BusinessDate}'";
                    ExchangeRate er = EntityUtils.GetEntityByPath<ExchangeRate>(path);
                    doc.ACToFCRate = er.Rate;//汇率
                }
            }

            //业务员/部门
            doc.Seller = EntityUtils.GetEntityByCode<Operators>(dto.Seller);
            if (doc.Seller != null)
            {
                doc.SaleDepartment = doc.Seller.Dept;
            }
            else
            {
                doc.SaleDepartment = EntityUtils.GetEntityByCode<Department>(dto.SaleDepartment);
            }

            //扩展字段处理
            if (dto.DescFlexField != null && doc.DescFlexField == null)
            {
                doc.DescFlexField = new UFIDA.U9.Base.FlexField.DescFlexField.DescFlexSegments();
            }
            DTOUtils.DTOPropCopy(dto.DescFlexField, doc.DescFlexField);

            //单头备注
            if (dto.Memo != null)
            {
                if (doc.SOMemoes != null && doc.SOMemoes.Count > 0)
                {
                    doc.SOMemoes[0].Description = dto.Memo;
                }
                else
                {
                    SOMemo memo = SOMemo.Create(doc);
                    memo.LineNO = 10;
                    memo.Description = dto.Memo;
                    memo.DocMemoType = DocMemoTypeEnum.DocHead;
                    memo.IsForAfterSold = true;
                    memo.IsForCustomer = true;
                    memo.IsForFinancial = true;
                    memo.IsForInv = true;
                    memo.IsForManufacture = true;
                    memo.IsForPurchase = true;
                    memo.IsForRD = true;
                    memo.IsForSupplier = true;
                }
            }

            //其它赋值
            doc.ShipRule = customer.ShippmentRule;//出货原则
            doc.ConfirmTerm = customer.ARConfirmTerm;//立账条件
            doc.ConfirmMode = doc.DocumentType.ConfirmMode;//立账方式
            doc.ConfirmAccording = doc.DocumentType.ConfirmAccording;//立账依据
            doc.InvoiceAccording = doc.DocumentType.InvoiceAccording;//开票依据
            doc.BusinessType = doc.DocumentType.BusinessType;//业务类型
            doc.IsFillDoc = dto.IsFillDoc;//补单
            doc.Memo = dto.Memo;
            doc.IsShipRuleChangeable = true;
            doc.IsPriceIncludeTax = true;
            doc.IsPreRecChangeable = true;
            doc.IsPLAlterable = true;
            doc.IsCreditCheck = true;
            doc.IsConfirmTermChangeable = true;
            doc.IsChangeableTCToACExchRate = true;
            doc.IsChangeableTC = true;
            doc.IsChangeableRateType = true;
            doc.IsChangeableAC = true;
            doc.SOPriority = SOPRIEnum.PRI99;
            doc.PreRecObject = PreRecObjectEnum.SO;
            //doc.Version = 1; //版本,订单变更时自动+1
            doc.IncomeConfirmRule = RevenueConfirmRuleEnum.SameToARCfm;
            doc.InsureRatio = 1.1M;
            doc.ErrorRate = 0.05M;

            return doc;
        }
    }
}
